#! /bin/bash

# 功能
# 单库备份或全备

MYSQL_HOST=127.0.0.1       # mysql 连接地址
MYSQL_PORT=3306            # mysql 连接端口
MYSQL_USER=root             # mysql 连接用户
MYSQL_PASSWORD='123456'    # mysql 连接密码

DATABASES='test test1 test2'  # 全量备份: 'ALL' / 备份库: 书写库名以空格分隔 例: 'test test1 test2'
BACKUP_PATH=/data     # 备份目录
BACKUP_SAVE_DAYS=30  # 备份保存天数
LOG_SAVE_DAYS=30     # 日志保存天数

MYSQL_TAG=11.11.11.2  # 想要在日志和告警中现实的信息



########## 微信告警配置 无需微信告警设置为 OFF 即可 ##########

enterprise_wechat_alarm=ON   # 开启: ON / 关闭: OFF    
enterprise_wechat_webhook_url="https://qyapi.weixin.qq.com/cgi-bin/webhook/dsdsdsdsdsdsds"   # 企业微信群机器人 webhook
enterprise_wechat_tag="${MYSQL_TAG}"   # 在微信告警中添加标识信息


########################## 默认配置 ##########################
# 无特殊情况 保持默认即可
LOG_PATH=${BACKUP_PATH}                    # 日志路径 默认在备份目录下
MYSQL_COMMAN_PATH="$(which mysql 2>/dev/null)"         # mysql 命令路径
MYSQLDUMP_COMMAN_PATH="$(which mysqldump 2>/dev/null)" # mysqldump 命令路径
MYSQL_CONN="${MYSQL_COMMAN_PATH} -u${MYSQL_USER} -h${MYSQL_HOST} -P${MYSQL_PORT} -p${MYSQL_PASSWORD} "  # mysql 参数拼接 
# mysqldump 参数拼接
MYSQLDUMP_CONN="${MYSQLDUMP_COMMAN_PATH}  -u${MYSQL_USER} -h${MYSQL_HOST} -P${MYSQL_PORT} -p${MYSQL_PASSWORD} -E -R --triggers --master-data=2 --single-transaction --set-gtid-purged=OFF  " 
BAK_DATETIME="$(date '+%Y%m%d%H%M%S')"                           # 时间
LOG_REDIRECTION=${LOG_PATH}/dump-log/1_dump_${BAK_DATETIME}.log  # 日志路径


# 写日志
log_message(){
    # log_message "测试信息" "error/info" 0/1
    local message_content="$1"
    local message_status="$2"
    local message_type=$3

    case $message_type in
    0)# 正常显示
        echo "$(date '+%Y-%m-%d %H:%M:%S') ${MYSQL_TAG}:${MYSQL_PORT} ${message_status}  ${message_content}"  >>${LOG_REDIRECTION}
        echo "$(date '+%Y-%m-%d %H:%M:%S') ${MYSQL_TAG}:${MYSQL_PORT} ${message_status}  ${message_content}"
        ;;
    1)# 格式化显示
        echo "$(date '+%Y-%m-%d %H:%M:%S') ${MYSQL_TAG}:${MYSQL_PORT} ${message_status}  ${message_content}"|fmt  >>${LOG_REDIRECTION}
        echo "$(date '+%Y-%m-%d %H:%M:%S') ${MYSQL_TAG}:${MYSQL_PORT} ${message_status}  ${message_content}"|fmt
        ;;
    *)# 其他的报错
        echo "$(date '+%Y-%m-%d %H:%M:%S') 日志类型错误 请检查报错"  >>${LOG_REDIRECTION}
        echo "$(date '+%Y-%m-%d %H:%M:%S') 日志类型错误 请检查报错"
        ;;
    esac
}

# 微信告警
wechat_alarm() {
	# wechat_alarm  "远程增备失败"
    if [ "$enterprise_wechat_alarm" == "ON" ];then
        alarm_check(){
            # 网络是否通畅
            ping -c 1 qyapi.weixin.qq.com  >/dev/null  2>&1
            if [ $? -ne 0 ];then
                LogWrite "网络不通 无法使用微信告警功能" "error"
            fi
        }
        alarm_check

        alarm_content="$1"
        curl "${enterprise_wechat_webhook_url}"  -H 'Content-Type: application/json'  -d "{\"msgtype\": \"text\",\"text\": {\"content\": \"${enterprise_wechat_tag}:${MYSQL_PORT} ${alarm_content}\"}}" 2>/dev/null |grep 'ok' >/dev/null 2>&1
        if [ $? -ne 0 ];then
            LogWrite "微信消息发送失败 请手动验证 webhook 是否正确" "error"
        fi
    fi
}


# 检查 mysql 连通性
check_mysql_conn() {
    $MYSQL_CONN -N -e 'select 1;' &>/dev/null
    if [ $? -ne 0 ];then
        echo 3
    else
        echo 1
    fi
}

# 检查文件或目录是否存在
check_path() {
    # check_path "/tmp/" "f/d"
    # 返回值 0 不存在  1 存在 2 类型输出错误
    local check_path="$1"
    local check_type="$2"

    case $check_type in
    f)# 文件检查
        if [ ! -f "$check_path" ];then
            echo 3
        else
            echo 1
        fi 
        ;;
    d)# 目录检查
        if [ ! -d "$check_path" ];then
            echo 3
        else
            echo 1
        fi 
        ;;
    *)# 输入错误
        echo 2
        ;;
    esac 
}


# 检查
backup_check() {
	local status=0

	local check_status=$(check_path "$BACKUP_PATH" 'd')
	if [[ $check_status -ne 1 ]];then
		log_message "mysql 备份目录不存在" "error" 0
		exit 1
	fi 

	local check_status=$(check_path "$LOG_PATH" 'd')
	if [ $check_status -ne 1 ];then
		log_message "日志目录不存在" "error" 0
		exit 1
	fi 

	if [ ! -d "${LOG_PATH}/dump-log" ];then
		mkdir ${LOG_PATH}/dump-log
	fi

	local check_status=$(check_path "$MYSQL_COMMAN_PATH" 'f')
	if [[ $check_status -ne 1 ]];then
		log_message "mysql 命令路径不存在" "error" 0
		status=1
	fi 

	local check_status=$(check_path "$MYSQLDUMP_COMMAN_PATH" 'f')
	if [[ $check_status -ne 1 ]];then
		log_message "mysqldump 命令路径不存在" "error" 0
		status=1
	fi 



	local check_status=$(check_mysql_conn)
	if [ $check_status -ne 1 ];then
        log_message "MySQL  连接失败 请检查连接信息" "error" 0
		status=1
	fi 


	# 备份类型判断
	local check_database_status=$(echo "$DATABASES" | grep -cE '^[a-zA-Z0-9_ ]*$')

	local check_full_status=$(echo "$DATABASES" | grep -cE '^[ ]*$')

	if [ "$DATABASES" == 'ALL' ] || [ "$check_full_status" -eq 1 ];then
		BACKUP_DATABASE='-A'
		BACKUP_TYPE='full'

	elif [ $check_database_status -eq 1 ]; then
		BACKUP_DATABASE="-B ${DATABASES}"
		BACKUP_TYPE='database'

	else
		log_message "DATABASES 参数指定参数错误" "error" 0
		status=1
	fi



	if [ $status -eq 1 ];then
		log_message "备份检查失败 请检查以上报错" "error" 0
		wechat_alarm "备份检查失败"
		exit 1
	fi
    log_message "备份检查已完成" "info" 0

}
backup_check


# 备份
backup_exec() {

	if [ "$BACKUP_TYPE" == 'full' ];then
		local output_message='全量'

	else
		local output_message="[${DATABASES}] 库"

	fi
	

	$MYSQLDUMP_CONN ${BACKUP_DATABASE}    2>${LOG_REDIRECTION}|gzip >${BACKUP_PATH}/dump-${MYSQL_TAG}-${MYSQL_PORT}-${BAK_DATETIME}-${BACKUP_TYPE}.sql.gz
	if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]]; then
		log_message "备份失败 请检查日志信息" "error" 0
		wechat_alarm "备份失败"
	else

		log_message "MySQL ${output_message}备份成功!" "info" 0
	fi
}
backup_exec

# 定期清理
backup_clean() {
	cd  ${BACKUP_PATH} && find ./  -type f -name "dump-${MYSQL_HOST}-${MYSQL_PORT}-*.sql.gz"  -mtime +${BACKUP_SAVE_DAYS} -print|xargs rm -f
	if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]];then
		log_message "备份清理失败" "info" 0
		wechat_alarm "备份清理失败"
	fi


	cd  ${LOG_PATH}/dump-log && find ./  -type f -name "1_dump_*.log"  -mtime +${LOG_SAVE_DAYS} -print|xargs rm -f
	if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]];then
		log_message "日志清理失败" "info" 0
		wechat_alarm "日志清理失败"
	fi
}
backup_clean


